#include "gtest/gtest.h"
#include "reader_buf.h"
#include "spdlog/spdlog.h"

using namespace simple;

int openFile(char *data, int size) {
    FILE *fp = fopen("tmp.txt", "w+");
    // 写入数据
    fwrite(data, sizeof(data[0]), size / sizeof(data[0]), fp);
    // 刷新缓存
    fflush(fp);
    // 移动指针到起始位置
    fseek(fp, 0L, SEEK_SET);
    // 根据文件指针, 返回文件句柄
    return fileno(fp);
}

/**
 * 读取单个字符
 */
TEST(reader_buf_test, readByte) {
    char data[] = "123456789abcd";
    int file_fd = openFile(data, sizeof(data));

    char buf[1] = {};
    ReaderBuff readerBuff(file_fd);
    for (char i: data) {
        EXPECT_EQ(readerBuff.readByte(buf), 1);
        EXPECT_EQ(*buf, i);
    }
    EXPECT_EQ(readerBuff.readByte(buf), 0);

    // 关闭io句柄
    close(file_fd);
    EXPECT_EQ(readerBuff.readByte(buf), -1);
}

/**
 * 读取多个字符, 缓冲区不打满
 */
TEST(reader_buf_test, readBytes) {
    char data[] = "123456789abcd";
    int file_fd = openFile(data, sizeof(data));

    int readOffset = 0;
    char buf[3] = {};
    ReaderBuff readerBuff(file_fd);
    for (int i = 0; i < sizeof(data); i += sizeof(buf)) {
        int readSize;
        if ((sizeof(data) - readOffset) >= sizeof(buf)) {
            readSize = sizeof(buf);
        } else {
            readSize = (int) sizeof(data) - readOffset;
        }

        EXPECT_EQ(readerBuff.readBytes(buf, sizeof(buf)), readSize);
        for (int j = 0; j < readSize; ++j) {
            spdlog::info("buf[{}] = {}, data[{}+{}]={}", j, buf[j], readOffset, j, data[readOffset + j]);
            EXPECT_EQ(buf[j], data[readOffset + j]);
        }
        readOffset += readSize;
    }
    EXPECT_EQ(readerBuff.readBytes(buf, sizeof(buf)), 0);

    // 关闭io句柄
    close(file_fd);
    EXPECT_EQ(readerBuff.readByte(buf), -1);
}

/**
 * 读取多个字符, 缓冲区打满
 */
TEST(reader_buf_test, readBytes2) {
    char data[] = "123456789abcd";
    int file_fd = openFile(data, sizeof(data));

    int readOffset = 0;
    char buf[2] = {};
    ReaderBuff readerBuff(file_fd, 3);
    for (int i = 0; i < sizeof(data); i += sizeof(buf)) {
        int readSize;
        if ((sizeof(data) - readOffset) >= sizeof(buf)) {
            readSize = sizeof(buf);
        } else {
            readSize = (int) sizeof(data) - readOffset;
        }

        EXPECT_EQ(readerBuff.readBytes(buf, sizeof(buf)), readSize);
        for (int j = 0; j < readSize; ++j) {
            spdlog::info("buf[{}] = {}, data[{}+{}]={}", j, buf[j], readOffset, j, data[readOffset + j]);
            EXPECT_EQ(buf[j], data[readOffset + j]);
        }
        readOffset += readSize;
    }
    EXPECT_EQ(readerBuff.readBytes(buf, sizeof(buf)), 0);

    // 关闭io句柄
    close(file_fd);
    EXPECT_EQ(readerBuff.readByte(buf), -1);
}

/**
 * 读取一行字符串, 换行符:\n
 */
TEST(reader_buf_test, readLine) {
    char data[] = {'a', 'b', 'c', '\n', 4, 5, 6, '\n', 7, 8, 9};
    int file_fd = openFile(data, sizeof(data));

    std::vector<char> buf;
    ReaderBuff readerBuff(file_fd);
    EXPECT_EQ(readerBuff.readLine(buf), 4);
    EXPECT_EQ(std::string(buf.data(), buf.size()), "abc\n");

    EXPECT_EQ(readerBuff.readLine(buf), 4);
    EXPECT_EQ(std::string(buf.data(), buf.size()), "\x4\x5\x6\n");

    EXPECT_EQ(readerBuff.readLine(buf), 0);

    // 关闭io句柄
    readerBuff.reset();
    close(file_fd);
    EXPECT_EQ(readerBuff.readLine(buf), -1);
}

/**
 * 读取一行字符串, 换行符:\r\n
 */
TEST(reader_buf_test, readLine2) {
    char data[] = {'a', 'b', 'c', '\r', '\n', 4, 5, 6, '\r', '\n', 1, 2, 3};
    int file_fd = openFile(data, sizeof(data));

    std::vector<char> buf;
    ReaderBuff readerBuff(file_fd);
    EXPECT_EQ(readerBuff.readLine(buf), 5);
    EXPECT_EQ(std::string(buf.data(), buf.size()), "abc\r\n");

    EXPECT_EQ(readerBuff.readLine(buf), 5);
    EXPECT_EQ(std::string(buf.data(), buf.size()), "\x4\x5\x6\r\n");

    EXPECT_EQ(readerBuff.readLine(buf), 0);

    // 关闭io句柄
    readerBuff.reset();
    close(file_fd);
    EXPECT_EQ(readerBuff.readLine(buf), -1);
}

/**
 * 读取一行字符串, 换行符:EOF
 */
TEST(reader_buf_test, readLine3) {
    char data[] = {'a', 'b', 'c', '\n', 4, 5, 6, '\n', 7, 8, 9};
    int file_fd = openFile(data, sizeof(data));

    std::vector<char> buf;
    ReaderBuff readerBuff(file_fd);
    EXPECT_EQ(readerBuff.readLine(buf), 4);
    EXPECT_EQ(readerBuff.readLine(buf, 3), 0);

    // 关闭io句柄
    readerBuff.reset();
    close(file_fd);
    EXPECT_EQ(readerBuff.readLine(buf), -1);

}

/**
 * 探测数据, 探测一部分
 */
TEST(reader_buf_test, peek_array) {
    char data[] = "123456789";
    int file_fd = openFile(data, sizeof(data));

    char buf[3] = {};
    ReaderBuff reader(file_fd, 6);
    EXPECT_EQ(reader.peek(buf, sizeof(buf)), sizeof(buf));
    for (int i = 0; i < sizeof(buf); ++i) {
        EXPECT_EQ(buf[i], data[i]);
        spdlog::info("buf[{}] = {}, data[{}]={}", i, buf[i], i, data[i]);
    }

    // 探测后检测指针没有变化
    EXPECT_EQ(reader.buffered(), reader.size());
}

/**
 * 探测数据, 全量探测
 */
TEST(reader_buf_test, peek_array2) {
    char data[] = "123456789";
    int file_fd = openFile(data, sizeof(data));

    char buf[6] = {};
    ReaderBuff reader(file_fd, 3);
    int n = reader.peek(buf, sizeof(buf));
    EXPECT_EQ(n, reader.buffered());
    for (int i = 0; i < n; ++i) {
        EXPECT_EQ(buf[i], data[i]);
        spdlog::info("buf[{}] = {}, data[{}]={}", i, buf[i], i, data[i]);
    }

    // 探测后检测指针没有变化
    EXPECT_EQ(reader.buffered(), reader.size());
}

TEST(reader_buf_test, peek_vector) {
    char data[] = "123456789";
    int file_fd = openFile(data, sizeof(data));

    std::vector<char> buf;
    ReaderBuff reader(file_fd, 6);

    EXPECT_EQ(reader.peek(buf, 3), 3);
    for (int i = 0; i < 3; ++i) {
        EXPECT_EQ(buf[i], data[i]);
        spdlog::info("buf[{}] = {}, data[{}]={}", i, buf[i], i, data[i]);
    }
    // 探测后检测指针没有变化
    EXPECT_EQ(reader.buffered(), reader.size());
}
